<template>
  <div>
    <!-- 上面三级联动card -->
    <el-card>
      <CategorySelector :disabled="!isShowList"></CategorySelector>
    </el-card>
    <el-card style="margin-top: 20px">
      <!-- 代表列表界面 -->
      <div v-show="isShowList">
        <el-button type="primary" icon="ele-Plus" @click="showAddDiv" :disabled="!category3Id">添加属性</el-button>
        <el-table :data="attrList" border stripe>
          <el-table-column label="序号" type="index" align="center" width="80">
          </el-table-column>
          <el-table-column label="属性名称" width="150" prop="attrName">
          </el-table-column>
          <el-table-column label="属性值名称列表">
            <template v-slot="{ row, $index }">
              <el-tag type="success" v-for="attrValue in row.attrValueList" :key="attrValue.id">
                {{ attrValue.valueName }}
              </el-tag>
            </template>
          </el-table-column>
          <el-table-column label="操作" width="150">
            <template v-slot="{ row, $index }">
              <el-button type="warning" size="small" icon="ele-Edit" title="修改" @click="showUpdateDiv(row)"></el-button>
              <el-popconfirm :title="`您确定要删除${row.attrName}吗？`" @confirm="deleteAttr(row)">
                <!-- 具名插槽 全写 :v-slot:reference  下面是简写 -->
                <template #reference>
                  <el-button type="danger" size="small" icon="ele-Delete" title="删除">
                  </el-button>
                </template>
              </el-popconfirm>

            </template>
          </el-table-column>
        </el-table>
      </div>
      <!-- 代表添加或者修改的界面 -->
      <div v-show="!isShowList">
        <el-form :inline="true">
          <el-form-item label="属性名">
            <el-input placeholder="输入属性名" v-model="attrForm.attrName"></el-input>
          </el-form-item>
        </el-form>
        <el-button type="primary" @click="addAttrValue" :disabled="!attrForm.attrName">添加属性值</el-button>
        <el-button @click="isShowList = true">取消</el-button>
        <el-table border stripe style="margin-top: 20px" :data="attrForm.attrValueList">
          <el-table-column label="序号" align="center" type="index" width="80">
          </el-table-column>
          <el-table-column label="属性值名称">
            <template v-slot="{row,$index}">
              <el-input ref="inputRef" v-model="row.valueName" size="small" @blur="toLook(row)"
                @keyup.enter="toLook(row)" v-if="row.isEdit">
              </el-input>
              <span style="display: block;width: 100%;height: 100%;" v-else
                @click="toEdit(row)">{{ row.valueName }}</span>
            </template>
          </el-table-column>
          <el-table-column label="操作">
            <template v-slot="{row,$index}">
              <el-popconfirm :title="`您确定要删除${row.attrName}吗？`" @confirm="attrForm.attrValueList.splice($index,1)">
                <!-- 具名插槽 全写 :v-slot:reference  下面是简写 -->
                <template #reference>
                  <el-button type="danger" size="small" icon="ele-Delete" title="删除">
                  </el-button>
                </template>
              </el-popconfirm>
            </template>
          </el-table-column>
        </el-table>
        <el-button type="primary" @click="save" :disabled="!attrForm.attrValueList.length">保存</el-button>
        <el-button @click="isShowList = true">取消</el-button>
      </div>
    </el-card>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import { ElMessage } from "element-plus";

export default defineComponent({
  name: "Attr", //组件名称
  // 1\开发着工具查找组件
  // 2\递归组件必须写名字
  // 3\全局注册组件
  // 4\keep-alive
});
</script>
<script lang="ts" setup>
import { ref, watch, nextTick } from "vue";
import { storeToRefs } from "pinia";
import type { AttrData, AttrValueData } from "@/api/attr";
import { useCategoryStore } from "@/stores/category";
import attrApi from "@/api/attr";
import cloneDeep from "lodash/cloneDeep";

const categoryStore = useCategoryStore();
const { category1Id, category2Id, category3Id } = storeToRefs(categoryStore);

const attrList = ref<AttrData[]>([]);

// 发请求获取平台属性列表
const getAttrList = async () => {
  try {
    const result = await attrApi.getList(
      category1Id.value as number,
      category2Id.value as number,
      category3Id.value as number
    );
    attrList.value = result;
  } catch (error) {
    ElMessage.error("获取平台属性列表失败");
  }
};
//-------------------------------------------
// ref reactive () => {}(监视reactive对象当中某个属性)     监视多个[前三种]
watch(
  category3Id,
  (newVal, oldVal) => {
    if (newVal === "") {
      // 说明三级id是空的,我们需要清空attrList
      attrList.value = [];
    } else {
      // 说明三级id是发生变化了而且不是空串,需要发请求
      getAttrList();
    }
  },
  {
    immediate: true,
  }
);

//--------------------------------------------
//收集添加属性的动态数据逻辑
//当前能拿到俩数据就是attrName(v-model)和categoryLevel=3
//categoryId初始化不能用上面数据，因为对方也是初始化数据，俩初始化数据不能互相使用
const attrForm = ref<AttrData>({
  attrName: "",
  categoryId: "",
  categoryLevel: 3,
  //属性值列表
  attrValueList: [],

  // {
  //   id:number,
  //   valueName:string,
  //   attrId:number,
  // }
});
//-------------------------------------------
const isShowList = ref(true);
// 点击添加属性
const showAddDiv = () => {
  isShowList.value = false;

  //解决添加收集数据完成后取消，数据还依然存在的bug
  //并且收集 这时onMounted已经完成，再拿初始化数据category3Id就没关系了
  attrForm.value = {
    attrName: "",
    categoryId: category3Id.value,
    categoryLevel: 3,
    attrValueList: [],
  };
};
//--------------------------------------
//点击修改属性，并需要回显数据
const showUpdateDiv = (row: AttrData) => {
  isShowList.value = false;
  attrForm.value = cloneDeep(row);
};
// --------------------------------------------
//收集添加属性
//1点击添加属性按钮
const inputRef = ref();
const addAttrValue = () => {
  attrForm.value.attrValueList.push({
    //添加无id属性
    valueName: "",
    attrId: attrForm.value.id,
    isEdit: true, //新添加的属性值后面显示为input
  });
  // nextTick********************非常重要
  // 数据的更新是同步的
  // 但是页面的更新是异步的(页面更新就是用的nextTick)
  // 数据同步更新完成就立马要拿到页面的真实dom去操作,我们是拿不到的,拿到的是undefined

  // nextTick官方说明是等待最近一次dom更新
  // 其实本质就是让我们操作真实dom的代码也变为异步排队排在页面更新的异步后面

  // nextTick源码当中其实就是还用微任务,把你要的操作变为异步,nextTick就是生成异步任务的
  // 注意:使用nextTick的时候一定要注意顺序,必须先更新数据,再操作dom
  nextTick(() => {
    inputRef.value.focus();
  });
};
// 在模版中操作的步骤
// 2\把这个属性值数组交给table去展示,一上来数组当中没有对象
// 那么此时table是空的,我们点击一次添加属性值,数组当中就会出现一行
// 这一行出现我们就可以出现input框,

// 3\通过在input身上的v-model + 作用域插槽,让用户输入添加的属性值名称

//点击span时切换成input 查看变编辑模式
const toEdit = (row: AttrValueData) => {
  row.isEdit = true;
  nextTick(() => {
    inputRef.value.focus();
  });
};

//input回车或失去焦点切换成span 编辑变查看模式
const toLook = (row: AttrValueData) => {
  //判断用户输入数据的合规性
  //数据是否为空
  if (row.valueName.trim() === "") {
    ElMessage.warning("输入的属性名称不可为空哦！");
    row.valueName = "";
    return;
  }
  //判断是否属性值名称列表内是否有重复属性名称数据
  //**** 当我们添加的一瞬，数据已放入数据列表，所以去除自身才能正确判断
  let isRepeat = attrForm.value.attrValueList.some((item) => {
    if (item !== row) {
      return item.valueName === row.valueName;
    }
  });
  if (isRepeat) {
    ElMessage.warning("属性值名称不能重复哦！");
    row.valueName = "";
    return;
  }
  row.isEdit = false;
};
//-----------------------------
//点击删除发请求了，删除平台属性
const deleteAttr = async (row: AttrData) => {
  try {
    await attrApi.delete(row.id as number);
    ElMessage.success("删除平台属性成功");
    getAttrList();
  } catch (error) {
    ElMessage.error("删除平台属性失败");
  }
};
//----------------------------------------
//收集数据
//点击保存进行保存操作
const save = async () => {
  // 1\获取收集的参数attrForm
  let attr = attrForm.value;
  // 2\整理参数：
  attr.attrValueList = attr.attrValueList.filter((item) => {
    // 			1、属性值名称如果为空串，从属性值列表当中去除
    // 			2、属性值当中去除isEdit属性
    if (item.valueName !== "") {
      delete item.isEdit;
      return true;
    }
  });
  // 			3、属性值列表如果没有属性值，不发请求
  if (!attr.attrValueList.length) return;

  try {
    // 3\发请求
    await attrApi.addOrUpdate(attr);
    // 4\成功   提示  返回列表  重新获取数据
    ElMessage.success("保存平台属性成功");
    isShowList.value = true;
    getAttrList();
  } catch (error) {
    // 5\失败   提示
    ElMessage.error("保存平台属性失败");
  }
};
</script>

<style lang="scss" scoped></style>